// Include standard headers
#include <stdio.h>
#include <stdlib.h>
//#include <iostream>

// Include GLEW
#include <GL/glew.h>
#include <opencv2/opencv.hpp>
// Include GLFW
#include <GLFW/glfw3.h>
#include <Eigen/Eigen>
// Include GLM
#include <glm/glm.hpp>
#include "dragon.h"
#include <glm/gtc/matrix_transform.hpp>
#include "readpng.h"
using namespace glm;

#include <common/shader.hpp>
#include <common/texture.hpp>
#include <common/controls.hpp>
#include <common/objloader.hpp>
#include <common/vboindexer.hpp>
#include <common/text2D.hpp>

#include <common/model.hpp>
#include <fstream>
#include <vector>

GLFWwindow* window;
void InitText(std::vector<std::string> picname, GLuint cubetext[6])
{
    glEnable(GL_TEXTURE_2D);
    for(int i=0;i<6;i++){
        std::string curname = picname[i];
        cubetext[i] = loadPNGTexture(curname.c_str());
        glBindTexture(GL_TEXTURE_2D, cubetext[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    }
    glDisable(GL_TEXTURE_2D);
}

void error_callback(int error, const char* description)
{
    puts(description);
}


int DrawTexCube(GLfloat width, GLfloat height, GLfloat depth, GLuint *cubetext)									//
{

    GLfloat x = width / 2, y = height / 2, z = depth / 2;
    glPushMatrix();
    // Front Face
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, cubetext[0]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);   glVertex3f(-x, -y, z);//Front
    glTexCoord2f(x, 0.0f);   glVertex3f(x, -y, z);
    glTexCoord2f(x, y);	glVertex3f(x, y, z);
    glTexCoord2f(0.0f, y);	glVertex3f(-x, y, z);
    glEnd();
    // Back Face
    glBindTexture(GL_TEXTURE_2D, cubetext[1]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);  glVertex3f(-x, -y, -z);
    glTexCoord2f(0.0f, y);  glVertex3f(-x, y, -z);
    glTexCoord2f(x, y);  glVertex3f(x, y, -z);
    glTexCoord2f(x, 0.0f);  glVertex3f(x, -y, -z);
    glEnd();
    // Top Face
    glBindTexture(GL_TEXTURE_2D, cubetext[2]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-x, y, -z);
    glTexCoord2f(0.0f, z); glVertex3f(-x, y, z);
    glTexCoord2f(x, z); glVertex3f(x, y, z);
    glTexCoord2f(x, 0.0f); glVertex3f(x, y, -z);
    glEnd();
    // Bottom Face
    glBindTexture(GL_TEXTURE_2D, cubetext[3]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-x, -y, -z);
    glTexCoord2f(x, 0.0f); glVertex3f(x, -y, -z);
    glTexCoord2f(x, z); glVertex3f(x, -y, z);
    glTexCoord2f(0.0f, z); glVertex3f(-x, -y, z);
    glEnd();
    // Right face
    glBindTexture(GL_TEXTURE_2D, cubetext[4]);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(x, -y, -z);
    glTexCoord2f(y, 0.0f); glVertex3f(x, y, -z);
    glTexCoord2f(y, z); glVertex3f(x, y, z);
    glTexCoord2f(0.0f, z); glVertex3f(x, -y, z);
    glEnd();
    // Left Face
    glBegin(GL_QUADS);
    glBindTexture(GL_TEXTURE_2D, cubetext[5]);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-x, -y, -z);
    glTexCoord2f(0.0f, z); glVertex3f(-x, -y, z);
    glTexCoord2f(x, z); glVertex3f(-x, y, z);
    glTexCoord2f(x, 0.0f); glVertex3f(-x, y, -z);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();
    return true;
}
const float PI = 3.1415;
int main(void)
{	
    // Initialise GLFW
	if (!glfwInit())
	{
		fprintf(stderr, "Failed to initialize GLFW\n");
		return -1;
	}

	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

	// Open a window and create its OpenGL context
	window = glfwCreateWindow( 1024, 768, "Tutorial 01", NULL, NULL);
	if (window==NULL)
	{
        fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	// Initialize GLEW
	glewExperimental = true; // Needed for core profile
	if (glewInit() != GLEW_OK) {
		fprintf(stderr, "Failed to initialize GLEW\n");
		return -1;
	}

	glfwSetWindowTitle(window,"Tutorial 01");

	// Ensure we can capture the escape key being pressed below
	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

	// Dark blue background
	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

	// Enable depth test
	glEnable(GL_DEPTH_TEST);
	// Accept fragment if it closer to the camera than the former one
	glDepthFunc(GL_LESS);

	GLuint VertexArrayID;
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);

	// Create and compile our GLSL program from the shaders
    GLuint programID = LoadShaders("vertexshader.sh",
                            "fragmentshader.sh");

	// Get a handle for our "MVP" uniform
	GLuint MatrixID = glGetUniformLocation(programID, "MVP");

	// Projection matrix : 45?Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
    glm::mat4 Projection = glm::perspective(90.0f, 4.0f / 3.0f, 0.1f, 1000.0f);
	// Camera matrix
    glLookat(
        0, 0, 12,
        0, 0, 0,
        0, 1, 0
		);

	//Mesh * cur_mesh = &ninja_head;
    Mesh * cur_mesh = &ninja_head;
    GLuint cubetext[6];
    InitText(picname, cubetext);
    do{
       // ninja_head.setAtrribute(Color, (void *)&colors[0], colors.size() * sizeof(glm::vec3));
		f(cur_mesh);
		// Clear the screen
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        DrawTexCube(32, 32, 32, cubetext);
		// Swap buffers
		glfwSwapBuffers(window);
		// Poll for and process events
		glfwPollEvents();
		
		glfwSetErrorCallback(error_callback);
		
	}// Check if the ESC key was pressed or the window was closed
	while (glfwGetKey(window,GLFW_KEY_ESCAPE) != GLFW_PRESS && 
		!glfwWindowShouldClose(window));

	// Cleanup VBO and shader
	glDeleteProgram(programID);
	glDeleteVertexArrays(1, &VertexArrayID);

	// Close OpenGL window and terminate GLFW
	glfwTerminate();

	return 0;
}

